using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;

namespace CS_raytracer
{
    public class CScene
    {
        public Dictionary<string, CMaterial> Materials = new Dictionary<string, CMaterial>();
        public List<CRenderableObject> Objects = new List<CRenderableObject>();
        public List<CLight> Lights = new List<CLight>();
        public void LoadObjects(string FileName, ref CCamera camera)
        {
            XmlTextReader reader = new XmlTextReader(FileName);
            XmlDocument Scene_XML = new XmlDocument(); 
            Scene_XML.Load(reader);
            reader.Close();
            XmlElement root = Scene_XML.DocumentElement;
            foreach (XmlElement Element in root.ChildNodes)
            {
		        if(Element.Name=="Camera_Info")
                {
                    foreach (XmlElement CameraInfoNode in Element.ChildNodes)
                    {
                        if(CameraInfoNode.Name=="Position")
                        {
                            foreach (XmlElement CameraPositionNode in CameraInfoNode.ChildNodes)
                            {
                                if(CameraPositionNode.Name=="X")
                                {
                                    camera.Position.x=double.Parse(CameraPositionNode.InnerText);
                                }
                                else if(CameraPositionNode.Name=="Y")
                                {
                                    camera.Position.y=double.Parse(CameraPositionNode.InnerText);
                                }
                                else if(CameraPositionNode.Name=="Z")
                                {
                                    camera.Position.z=double.Parse(CameraPositionNode.InnerText);
                                }
                            }                    
                        }
                        else if(CameraInfoNode.Name=="LookAt")
                        {
                            foreach (XmlElement CameraLookAtNode in CameraInfoNode.ChildNodes)
                            {
                                if(CameraLookAtNode.Name=="X")
                                {
                                    camera.LookAt.x=double.Parse(CameraLookAtNode.InnerText);
                                }
                                else if(CameraLookAtNode.Name=="Y")
                                {
                                    camera.LookAt.y=double.Parse(CameraLookAtNode.InnerText);
                                }
                                else if(CameraLookAtNode.Name=="Z")
                                {
                                    camera.LookAt.z=double.Parse(CameraLookAtNode.InnerText);
                                }
                            }                    
                        }
                        else if (CameraInfoNode.Name == "FOV")
                        {
                            camera.SetFOV(double.Parse(CameraInfoNode.InnerText));
                        }
                    }                    
                }
                else if (Element.Name == "Object")
                {
                    string Type = Element.GetAttribute("Type");
                    switch (Type)
                    {
                        case "SPHERE":
                            CSphereObject SphereObj = new CSphereObject();
                            foreach (XmlElement ObjectInfoNode in Element.ChildNodes)
                            {
                                if (ObjectInfoNode.Name == "Negative")
                                {
                                    SphereObj.NegativeObject = bool.Parse(ObjectInfoNode.InnerText);
                                }
                                else if (ObjectInfoNode.Name == "Material")
                                {
                                    string MatName = ObjectInfoNode.InnerText;
                                    SphereObj.Material = Materials[MatName];
                                }
                                else if (ObjectInfoNode.Name == "Position")
                                {
                                    foreach (XmlElement ObjectPositionNode in ObjectInfoNode.ChildNodes)
                                    {
                                        if (ObjectPositionNode.Name == "X")
                                        {
                                            SphereObj.Position.x = double.Parse(ObjectPositionNode.InnerText);
                                        }
                                        else if (ObjectPositionNode.Name == "Y")
                                        {
                                            SphereObj.Position.y = double.Parse(ObjectPositionNode.InnerText);
                                        }
                                        else if (ObjectPositionNode.Name == "Z")
                                        {
                                            SphereObj.Position.z = double.Parse(ObjectPositionNode.InnerText);
                                        }
                                    }
                                }
                                else if (ObjectInfoNode.Name == "Radius")
                                {
                                    SphereObj.Radius = double.Parse(ObjectInfoNode.InnerText);
                                }
                            }
                            Objects.Add(SphereObj);
                            break;
                        case "METAOBJECT":
                            CMetaObject MetaObj = new CMetaObject();
                            MetaObj.NegativeObject = false;
                            foreach (XmlElement ObjectInfoNode in Element.ChildNodes)
                            {
                                if (ObjectInfoNode.Name == "CENTER")
                                {
                                    CVector pos = new CVector();
                                    CMaterial mat = new CMaterial();
                                    double rad = 0.0;
                                    foreach (XmlElement CenterNode in ObjectInfoNode.ChildNodes)
                                    {
                                        if (CenterNode.Name == "Position")
                                        {
                                            foreach (XmlElement ObjectPositionNode in CenterNode.ChildNodes)
                                            {
                                                if (ObjectPositionNode.Name == "X")
                                                {
                                                    pos.x = -double.Parse(ObjectPositionNode.InnerText);
                                                }
                                                else if (ObjectPositionNode.Name == "Y")
                                                {
                                                    pos.y = double.Parse(ObjectPositionNode.InnerText);
                                                }
                                                else if (ObjectPositionNode.Name == "Z")
                                                {
                                                    pos.z = -double.Parse(ObjectPositionNode.InnerText);
                                                }
                                            }
                                        }
                                        else if (CenterNode.Name == "Material")
                                        {
                                            string MatName = CenterNode.InnerText;
                                            mat = Materials[MatName];
                                        }
                                        else if (CenterNode.Name == "Radius")
                                        {
                                            rad = double.Parse(CenterNode.InnerText);
                                        }
                                    }
                                    MetaObj.AddCenter(pos,mat,rad);
                                }

                            }
                            Objects.Add(MetaObj);
                            break;
                    }
                }
                else if (Element.Name == "Light")
                {
                    string Type = Element.GetAttribute("Type");
                    switch (Type)
                    {
                        case "POINT_LIGHT":
                            CLight LightObj = new CLight();
                            foreach (XmlElement LightInfoNode in Element.ChildNodes)
                            {
                                if (LightInfoNode.Name == "Intensity")
                                {
                                    foreach (XmlElement ColorNode in LightInfoNode.ChildNodes)
                                    {
                                        if (ColorNode.Name == "Red")
                                        {
                                            LightObj.Intensity.r = double.Parse(ColorNode.InnerText);
                                        }
                                        else if (ColorNode.Name == "Green")
                                        {
                                            LightObj.Intensity.g = double.Parse(ColorNode.InnerText);
                                        }
                                        else if (ColorNode.Name == "Blue")
                                        {
                                            LightObj.Intensity.b = double.Parse(ColorNode.InnerText);
                                        }
                                    }
                                }
                                else if (LightInfoNode.Name == "Position")
                                {
                                    foreach (XmlElement LightPositionNode in LightInfoNode.ChildNodes)
                                    {
                                        if (LightPositionNode.Name == "X")
                                        {
                                            LightObj.Position.x = double.Parse(LightPositionNode.InnerText);
                                        }
                                        else if (LightPositionNode.Name == "Y")
                                        {
                                            LightObj.Position.y = double.Parse(LightPositionNode.InnerText);
                                        }
                                        else if (LightPositionNode.Name == "Z")
                                        {
                                            LightObj.Position.z = double.Parse(LightPositionNode.InnerText);
                                        }
                                    }
                                }
                            }
                            Lights.Add(LightObj);
                            break;
                    }
                }
            }
        }
        public void GenerateSphereScene(int numSpheres)
        {
            Objects.Clear();
            CSphereObject SphereObj1 = new CSphereObject();
            SphereObj1.Material = Materials["BlueShine"];
            SphereObj1.Position.x = 0.0;
            SphereObj1.Position.y = -30000.0;
            SphereObj1.Position.z = 0.0;
            SphereObj1.Radius = 29990.0;
            Objects.Add(SphereObj1);
            for (int i = 0; i < numSpheres; ++i)
            {
                CSphereObject SphereObj = new CSphereObject();
                SphereObj.Material = Materials["RedShine"];
                SphereObj.Position.x = 30 *  Math.Cos(i * Math.PI*2.0/numSpheres);
                SphereObj.Position.y = 0.0;
                SphereObj.Position.z = 30 * Math.Sin(i * Math.PI * 2.0 / numSpheres);
                SphereObj.Radius = 1.0;
                Objects.Add(SphereObj);
                CLight LightObj = new CLight();
                LightObj.Intensity.r = 1.0;
                LightObj.Intensity.g = 1.0;
                LightObj.Intensity.b = 1.0;
                LightObj.Position.x = 60 * Math.Cos(i * Math.PI * 2.0 / numSpheres);
                LightObj.Position.y = 10.0;
                LightObj.Position.z = 60 * Math.Sin(i * Math.PI * 2.0 / numSpheres);
                Lights.Add(LightObj);
            }
        }
        public void LoadMaterials(string FileName)
        {
            XmlTextReader reader = new XmlTextReader(FileName);
            XmlDocument Materials_XML = new XmlDocument(); 
            Materials_XML.Load(reader);
            reader.Close();
            XmlElement root = Materials_XML.DocumentElement;
            foreach (XmlElement Mat in root.ChildNodes)
            {
		        CMaterial Material = new CMaterial();
                string name ="";
                foreach (XmlElement MatInfo in Mat.ChildNodes)
                {
                    if(MatInfo.Name=="Name")
                    {
                        name=MatInfo.InnerText;
                    }
                    else if(MatInfo.Name=="Color")
                    {
                        foreach (XmlElement ColorNode in MatInfo.ChildNodes)
                        {
                            if(ColorNode.Name=="Red")
                            {
                                Material.color.r=double.Parse(ColorNode.InnerText);
                            }
                            else if(ColorNode.Name=="Green")
                            {
                                Material.color.g=double.Parse(ColorNode.InnerText);
                            }
                            else if(ColorNode.Name=="Blue")
                            {
                                Material.color.b=double.Parse(ColorNode.InnerText);
                            }
                        }
                    }
                    else if(MatInfo.Name=="Diffuse")
                    {
                        Material.diffuse = double.Parse(MatInfo.InnerText);
                    }
                    else if(MatInfo.Name=="Specular")
                    {
                        foreach (XmlElement SpecularNode in MatInfo.ChildNodes)
                        {
                            if (SpecularNode.Name == "Value")
                            {
                                Material.specular = double.Parse(SpecularNode.InnerText);
                            }
                            else if (SpecularNode.Name == "Exponent")
                            {
                                Material.specularExponent = int.Parse(SpecularNode.InnerText);
                            }
                        }
                    }
                    else if(MatInfo.Name=="Reflection")
                    {
                        foreach (XmlElement ReflectionNode in MatInfo.ChildNodes)
                        {
                            if (ReflectionNode.Name == "Red")
                            {
                                Material.reflection.r = double.Parse(ReflectionNode.InnerText);
                            }
                            else if (ReflectionNode.Name == "Green")
                            {
                                Material.reflection.g = double.Parse(ReflectionNode.InnerText);
                            }
                            else if (ReflectionNode.Name == "Blue")
                            {
                                Material.reflection.b = double.Parse(ReflectionNode.InnerText);
                            }
                            else if (ReflectionNode.Name == "Scatter")
                            {
                                Material.reflectionScatter = double.Parse(ReflectionNode.InnerText);
                            }
                        }
                    }
                    else if(MatInfo.Name=="Transparency")
                    {
                        foreach (XmlElement TransparencyNode in MatInfo.ChildNodes)
                        {
                            if (TransparencyNode.Name == "Value")
                            {
                                Material.transparency = double.Parse(TransparencyNode.InnerText);
                            }
                            else if (TransparencyNode.Name == "RefractionIndex_Red")
                            {
                                Material.refractionIndex.r = double.Parse(TransparencyNode.InnerText);
                            }
                            else if (TransparencyNode.Name == "RefractionIndex_Green")
                            {
                                Material.refractionIndex.g = double.Parse(TransparencyNode.InnerText);
                            }
                            else if (TransparencyNode.Name == "RefractionIndex_Blue")
                            {
                                Material.refractionIndex.b = double.Parse(TransparencyNode.InnerText);
                            }
                        }
                    }
                }
		        Materials.Add(name,Material);
            }
        }

        public void PutMaterialsInList(ref System.Windows.Forms.ComboBox MaterialList)
        {
            foreach (KeyValuePair<string,CMaterial> mat in Materials)
            {
                MaterialList.Items.Add(mat.Key);
            }
        }
        
        public CMaterial GetMaterial(string materialName)
        {
            return Materials[materialName];
        }
        
        public void SetMaterial(string materialName, CMaterial mat)
        {
            Materials[materialName] = mat;
        }
        
        public bool TestRay(CRay Ray)
        {
            foreach (CRenderableObject Obj in Objects)
            {
                if (Obj.HitDistance(Ray) < Constants.Infinity)
                {
                    return true;
                }
            }
            return false;
        }
        public void RenderRay(CRay Ray, ref CColor ResultColor)
        {
            CRay Ray2 = Ray;
            CMaterial Mat = new CMaterial();
            double MinimumDistance = Constants.Infinity;
            double DistanceToSurface = 0;
            CRenderableObject ClosestObject = null;
            ResultColor.r = 0.0;
            ResultColor.g = 0.0;
            ResultColor.b = 0.0;
            CColor colorD = new CColor();
            CColor colorR = new CColor();
            CColor colorRefr = new CColor();
            CRay NormalRay = new CRay();
            foreach (CRenderableObject Obj in Objects)
            {
                double Distance = Obj.HitDistance(Ray2);
                if (Distance > Constants.eps && Distance < MinimumDistance)
                {
                    MinimumDistance = Distance;
                    ClosestObject = Obj;
                }
            }

            if (ClosestObject != null)
            {
                //		if(DistanceToSurface==0)
                DistanceToSurface += MinimumDistance;
                CColor DiffuseColor = new CColor();
                CColor SpecularColor = new CColor();
                CVector ImpactPoint = new CVector(Ray.Origin.x + DistanceToSurface * Ray.Direction.x, Ray.Origin.y + DistanceToSurface * Ray.Direction.y, Ray.Origin.z + DistanceToSurface * Ray.Direction.z);
                ClosestObject.GetNormal(ImpactPoint, out NormalRay);
                ClosestObject.GetMaterial(ImpactPoint, out Mat);
                //ImpactPoint+=NormalRay.Direction*eps;
                foreach (CLight Light in Lights)
                {
                    if (SeeLight(ImpactPoint, Light))
                    {
                        CVector ToLightVector = new CVector(Light.Position.x - ImpactPoint.x, Light.Position.y - ImpactPoint.y, Light.Position.z - ImpactPoint.z);
                        ToLightVector.Normalize();
                        double cosAngle = NormalRay.Direction.DotProduct(ToLightVector);
                        if (cosAngle > 0)
                        {
                            DiffuseColor = Mat.color * cosAngle * Mat.diffuse;

                            CRay ReflectedLight = new CRay();
                            ReflectedLight.Origin = ImpactPoint;
                            double dp2 = 2 * ToLightVector.DotProduct(NormalRay.Direction);
                            ReflectedLight.Direction = ToLightVector - (NormalRay.Direction * dp2);

                            double dot = ReflectedLight.Direction.DotProduct(Ray.Direction);
                            if (dot > 0)
                            {
                                SpecularColor.r = Math.Pow(dot, Mat.specularExponent) * Mat.specular;
                                SpecularColor.g = SpecularColor.r;
                                SpecularColor.b = SpecularColor.r;
                            }
                            SpecularColor *= Light.Intensity;
                        }
                        else
                        {
                            DiffuseColor.r = 0.0;
                            DiffuseColor.g = 0.0;
                            DiffuseColor.b = 0.0;
                            SpecularColor.r = 0.0;
                            SpecularColor.g = 0.0;
                            SpecularColor.b = 0.0;
                        }
                        colorD = colorD + (DiffuseColor + SpecularColor) * Light.Intensity;
                    }
                }
                if (ClosestObject.Selected)
                    colorD = new CColor(1.0, 0.5, 1.0);

                //		colorD+=Ambiant*Mat.color;
                /*		double AOComponent = pow(
                            1.0-exp(-1.0*AO(NormalRay,ClosestObject)*AO_Exposure)
                            ,AO_POW)*AO_STRENGHT;
                        colorD+=Mat.color*Ambiant*AOComponent;
                */
                /*#if RADIOSITY
                        // RADIOSITY - START
                            {
                                CColor RadColor;
                                RadColor.r =0.0;
                                RadColor.g =0.0;
                                RadColor.b =0.0;
                                CRay LocalRay;
                                LocalRay.Origin = ImpactPoint;
                                LocalRay.Direction = NormalRay.Direction;
                                CVector RN1 = CVector(LocalRay.Direction.z,LocalRay.Direction.y,-LocalRay.Direction.x);
                                CVector RN2 = LocalRay.Direction.CrossProduct(RN1);
                                LocalRay.intensity = Ray.intensity;
                                LocalRay.BounceThreshold=Ray.BounceThreshold-1;
                                if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > IntensityThreshold))
                                {
                                    for(int scat=0;scat<int((DIFFUSE_REFLECTION_COUNT/(1.0f*(MaxBounce-LocalRay.BounceThreshold+1)*(1+MaxBounce-LocalRay.BounceThreshold))));++scat)
                                    {
                                        double xoffs, yoffs;
                                        do 
                                        {
                                            xoffs = 10.0f*(rand()*2.0f/RAND_MAX-1.0)*(rand()*2.0f/RAND_MAX-1.0);
                                            yoffs = 10.0f*(rand()*2.0f/RAND_MAX-1.0)*(rand()*2.0f/RAND_MAX-1.0);
                                        } while((xoffs*xoffs+yoffs*yoffs)>(10.0f*10.0f));
                                        CRay R = LocalRay;
                                        R.Direction = R.Direction + RN1 * xoffs+RN2 * yoffs;
                                        R.Direction.Normalize();
                                        CColor colorR2;
                                        RenderRay(R,colorR2);
                                        RadColor+=colorR2;
                                    }
                                    RadColor *= 1.0f/(DIFFUSE_REFLECTION_COUNT/(1.0f*(MaxBounce-LocalRay.BounceThreshold+1.0f)*(MaxBounce-LocalRay.BounceThreshold)));
                                    RadColor *= Mat.color;

                                }				
                                colorD += RadColor;
                            }
                        // RADIOSITY - END
                #endif*/


                        // REFLECTION - START
                        if(Mat.reflection.r+Mat.reflection.g+Mat.reflection.b>0.0)
                        {
                            if(Mat.reflectionScatter==0.0f)
                            {
                                CRay LocalRay = new CRay();
                                LocalRay.Origin = ImpactPoint;
                                double dp2 = 2*Ray.Direction.DotProduct(NormalRay.Direction);
                                LocalRay.Direction = Ray.Direction-(NormalRay.Direction*dp2);
                                LocalRay.intensity = (Mat.reflection.r+Mat.reflection.g+Mat.reflection.b)*Ray.intensity;
                                LocalRay.BounceThreshold=Ray.BounceThreshold-1;
                                if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > Constants.IntensityThreshold))
                                {
                                    RenderRay(LocalRay,ref colorR);
                                    colorR *=Mat.reflection;
                                }
                                else
                                {
                                    colorR.r =0.0;
                                    colorR.g =0.0;
                                    colorR.b =0.0;
                                }
                            }
                            else
                            {
                                colorR.r =0.0;
                                colorR.g =0.0;
                                colorR.b =0.0;
//                                 CRay LocalRay;
//                                 LocalRay.Origin = ImpactPoint;
//                                 double dp2 = 2*Ray.Direction.DotProduct(NormalRay.Direction);
//                                 LocalRay.Direction = Ray.Direction-(NormalRay.Direction*dp2);
//                                 CVector RN1 = CVector(LocalRay.Direction.z,LocalRay.Direction.y,-LocalRay.Direction.x);
//                                 CVector RN2 = LocalRay.Direction.CrossProduct(RN1);
//                                 LocalRay.intensity = (Mat.reflection.r+Mat.reflection.g+Mat.reflection.b)*Ray.intensity;
//                                 LocalRay.BounceThreshold=Ray.BounceThreshold-1;
//                                 if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > IntensityThreshold))
//                                 {
//                                     for(int scat=0;scat<int((Constants.DiffuseReflectionCount/(1.0f*(MaxBounce-LocalRay.BounceThreshold+1)*(1+MaxBounce-LocalRay.BounceThreshold))));++scat)
//                                     {
//                                         double xoffs, yoffs;
//                                         do 
//                                         {
//                                             xoffs = Mat.reflectionScatter*(rand()*2.0f/RAND_MAX-1.0)*(rand()*2.0f/RAND_MAX-1.0)*(rand()*2.0f/RAND_MAX-1.0);
//                                             yoffs = Mat.reflectionScatter*(rand()*2.0f/RAND_MAX-1.0)*(rand()*2.0f/RAND_MAX-1.0)*(rand()*2.0f/RAND_MAX-1.0);
//                                         } while((xoffs*xoffs+yoffs*yoffs)>(Mat.reflectionScatter*Mat.reflectionScatter));
//                                         CRay R = LocalRay;
//                                         R.Direction = R.Direction + RN1 * xoffs+RN2 * yoffs;
//                                         R.Direction.Normalize();
//                                         CColor colorR2;
//                                         RenderRay(R,ref colorR2);
//                                         colorR+=colorR2;
//                                     }
//                                     colorR *= 1.0/(DIFFUSE_REFLECTION_COUNT/(1.0f*(MaxBounce-LocalRay.BounceThreshold+1)*(1+MaxBounce-LocalRay.BounceThreshold)));
//                                     colorR *= Mat.reflection;
// 
//                                 }					
                            }
                        }
                        else
                        {
                            colorR.r =0.0;
                            colorR.g =0.0;
                            colorR.b =0.0;
                        }

                        // REFLECTION - END


                /*
                        Chrono.reset();
                    // REFRACTION - START
                        if(Mat.transparency>0.0)
                        {
                            colorRefr.r =0.0;
                            colorRefr.g =0.0;
                            colorRefr.b =0.0;
                            if(Mat.refractionIndex.r!=Mat.refractionIndex.g || Mat.refractionIndex.r!=Mat.refractionIndex.b)
                            {
                            {//Computing for Red
                                CRay LocalRay;
                                LocalRay.Origin = ImpactPoint;
                                double nDiv = Mat.refractionIndex.r;
                                CVector incedent = Ray.Direction;
                                double cosI = -NormalRay.Direction.DotProduct(incedent);
                                if(cosI<0)
                                    nDiv = 1/nDiv ;
                                double sinI = sqrt(1.0f - cosI*cosI);
                                double sin2R = sinI/nDiv * sinI/nDiv;
                                if (sin2R < 1.0f) {
                                    CVector intRefrac;
                                    double coefficient = (sqrt(1.0f-sin2R)-nDiv*cosI);
                                    intRefrac = (incedent*nDiv) - (NormalRay.Direction*coefficient);
                                    intRefrac.Normalize();
                                    //new ray based on intersect point and calculated refraction
                                    LocalRay.Direction = intRefrac;

                                    LocalRay.intensity = Mat.transparency*Ray.intensity;
                                    LocalRay.BounceThreshold=Ray.BounceThreshold-1;
                                    if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > IntensityThreshold))
                                    {
                                        CColor colorRefrComponent;
                                        RenderRay(LocalRay,colorRefrComponent);
                                        colorRefrComponent *=Mat.color*Mat.transparency;
                                        colorRefrComponent *=CColor(1.0,0,0);
                                        colorRefr+=colorRefrComponent;
                                    }
                                }
                            }
                            {//Computing for Green
                                CRay LocalRay;
                                LocalRay.Origin = ImpactPoint;
                                double nDiv = Mat.refractionIndex.g;
                                CVector incedent = Ray.Direction;
                                double cosI = -NormalRay.Direction.DotProduct(incedent);
                                if(cosI<0)
                                    nDiv = 1/nDiv ;
                                double sinI = sqrt(1.0f - cosI*cosI);
                                double sin2R = sinI/nDiv * sinI/nDiv;
                                if (sin2R < 1.0f) {
                                    CVector intRefrac;
                                    double coefficient = (sqrt(1.0f-sin2R)-nDiv*cosI);
                                    intRefrac = (incedent*nDiv) - (NormalRay.Direction*coefficient);
                                    intRefrac.Normalize();
                                    //new ray based on intersect point and calculated refraction
                                    LocalRay.Direction = intRefrac;

                                    LocalRay.intensity = Mat.transparency*Ray.intensity;
                                    LocalRay.BounceThreshold=Ray.BounceThreshold-1;
                                    if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > IntensityThreshold))
                                    {
                                        CColor colorRefrComponent;
                                        RenderRay(LocalRay,colorRefrComponent);
                                        colorRefrComponent *=Mat.color*Mat.transparency;
                                        colorRefrComponent *=CColor(0,1.0,0);
                                        colorRefr+=colorRefrComponent;
                                    }
                                }
                            }
                            {//Computing for Blue
                                CRay LocalRay;
                                LocalRay.Origin = ImpactPoint;
                                double nDiv = Mat.refractionIndex.b;
                                CVector incedent = Ray.Direction;
                                double cosI = -NormalRay.Direction.DotProduct(incedent);
                                if(cosI<0)
                                    nDiv = 1/nDiv ;
                                double sinI = sqrt(1.0f - cosI*cosI);
                                double sin2R = sinI/nDiv * sinI/nDiv;
                                if (sin2R < 1.0f) {
                                    CVector intRefrac;
                                    double coefficient = (sqrt(1.0f-sin2R)-nDiv*cosI);
                                    intRefrac = (incedent*nDiv) - (NormalRay.Direction*coefficient);
                                    intRefrac.Normalize();
                                    //new ray based on intersect point and calculated refraction
                                    LocalRay.Direction = intRefrac;

                                    LocalRay.intensity = Mat.transparency*Ray.intensity;
                                    LocalRay.BounceThreshold=Ray.BounceThreshold-1;
                                    if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > IntensityThreshold))
                                    {
                                        CColor colorRefrComponent;
                                        RenderRay(LocalRay,colorRefrComponent);
                                        colorRefrComponent *=Mat.color*Mat.transparency;
                                        colorRefrComponent *=CColor(0,0,1.0);
                                        colorRefr+=colorRefrComponent;
                                    }
                                }
                            }
                            }
                            else
                            {
                                {//Computing for all Channels
                                    CRay LocalRay;
                                    LocalRay.Origin = ImpactPoint;
                                    double nDiv = Mat.refractionIndex.b;
                                    CVector incedent = Ray.Direction;
                                    double cosI = -NormalRay.Direction.DotProduct(incedent);
                                    if(cosI<0)
                                        nDiv = 1/nDiv ;
                                    double sinI = sqrt(1.0f - cosI*cosI);
                                    double sin2R = sinI/nDiv * sinI/nDiv;
                                    if (sin2R < 1.0f) {
                                        CVector intRefrac;
                                        double coefficient = (sqrt(1.0f-sin2R)-nDiv*cosI);
                                        intRefrac = (incedent*nDiv) - (NormalRay.Direction*coefficient);
                                        intRefrac.Normalize();
                                        //new ray based on intersect point and calculated refraction
                                        LocalRay.Direction = intRefrac;

                                        LocalRay.intensity = Mat.transparency*Ray.intensity;
                                        LocalRay.BounceThreshold=Ray.BounceThreshold-1;
                                        if ((LocalRay.BounceThreshold>0)&&(LocalRay.intensity > IntensityThreshold))
                                        {
                                            CColor colorRefrComponent;
                                            RenderRay(LocalRay,colorRefrComponent);
                                            colorRefrComponent *=Mat.color*Mat.transparency;
                                            colorRefr+=colorRefrComponent;
                                        }
                                    }
                                }

                            }
                        }
                        else
                        {
                            colorRefr.r =0.0;
                            colorRefr.g =0.0;
                            colorRefr.b =0.0;
                        }
                        Globals::Instance().RefractionTime+=Chrono.milliseconds();

                        // REFRACTION - END
                */

                ResultColor = (colorD + colorR + colorRefr);

            }
        }
        public bool SeeLight(CVector ImpactPoint, CLight Light)
        {
            double MinimumDistance = ImpactPoint.Distance(Light.Position);
            if (Light.Type == CLight.ELightType.LightType_Spot)
            {
                CVector DirectionToPoint = ImpactPoint - Light.Position;
                DirectionToPoint.Normalize();
                if (DirectionToPoint.DotProduct(Light.Direction) < Math.Cos(Light.ConeAngle / 360.0f * Math.PI))
                    return false;
            }
            CRay LightRay = new CRay();
            LightRay.Origin = /*Light->Position;*/ImpactPoint;
            LightRay.Direction = Light.Position - ImpactPoint/*ImpactPoint-Light->Position*/;
            LightRay.Direction.Normalize();
            double MinimumDistanceLight = MinimumDistance;
            foreach (CRenderableObject Obj in Objects)
            {
                double Distance = Obj.HitDistance(LightRay);
                if ((Distance < MinimumDistance - Constants.eps) && (Distance > Constants.eps))
                {
                    return false;
                }
            }
            return true;
        }

        public CRenderableObject Scene_GetObject(CRay view)
        {
            return null;
        }

    }
}
